package org.dbstar.scheduler.control.db.catalog;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.dbstar.scheduler.beans.Catalog;
import org.dbstar.scheduler.control.CatalogController;
import org.dbstar.scheduler.control.db.JdbcTemplateDao;
import org.dbstar.scheduler.control.exception.DaoException;
import org.springframework.jdbc.core.JdbcTemplate;


/**
 * 使用JdbcTemplate的CatalogController实现类。
 * 
 * @author 代波
 * @since 1.0.0
 * @version 1.0.0
 * @date 2012-4-21
 */
public class JdbcTemplateCatalogController extends JdbcTemplateDao implements CatalogController {
	private final CataLogQueryByRoot root;
	private final CataLogQuery queryAll;
	private final CataLogQueryByParent queryByParent;
	private final CataLogQueryById queryById;
	private final CatalogInsert insert;
	private final CatalogUpdate update;
	private final CatalogMove move;
	private final CatalogDelete delete;

	public JdbcTemplateCatalogController(JdbcTemplate jt) {
		super(jt);
		this.root = new CataLogQueryByRoot(jt);
		this.queryAll = new CataLogQuery(jt, "ORDER BY PARENT, ID");
		this.queryByParent = new CataLogQueryByParent(jt);
		this.queryById = new CataLogQueryById(jt);
		this.insert = new CatalogInsert(jt);
		this.update = new CatalogUpdate(jt);
		this.move = new CatalogMove(jt);
		this.delete = new CatalogDelete(jt);
	}

	@Override
	public Catalog getRootCatalog() throws DaoException {
		try {
			return root.findRoot();
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	@Override
	public List<Catalog> getAllCatalogs() throws DaoException {
		try {
			return queryAll.execute();
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	@Override
	public List<Catalog> getSubCatalogs(int parent) throws DaoException {
		try {
			return queryByParent.execute(parent);
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	@Override
	public Catalog getCatalog(int id) throws DaoException {
		try {
			return queryById.findObject(id);
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	@Override
	public int addCatalog(Catalog cataLog) throws DaoException {
		checkCatalog(cataLog, false);

		int oldId = cataLog.getId();
		Long oldMt = cataLog.getModifyTime();
		int result;
		try {
			result = insert.insertCatalog(cataLog);
			cataLog.setId(result);
			cataLog.setModifyTime(null);
		} catch (Throwable e) {
			throw new DaoException(e);
		}
		// 如果新增的自增ID的值，正好等于parent值，这时也会插入成功，且这条记录将无法被正常删除
		if (cataLog.getParent() == result) {
			// 先把parent更新为其他值，才能删除
			cataLog.setParent(null);
			updateCatalog(cataLog);
			removeCatalog(result);
			cataLog.setId(oldId);
			cataLog.setParent(result);
			cataLog.setModifyTime(oldMt);
			throw new DaoException("Parent Catalog not exist.");
		}
		return result;
	}

	private void checkCatalog(Catalog cataLog, boolean update) throws DaoException {
		if (cataLog.getParent() == null) {
			throw new DaoException("Catalog's parent must set.");
		}
		if (StringUtils.isBlank(cataLog.getName())) {
			throw new DaoException("Catalog's name can not blank.");
		}
		if (update) {
			if (cataLog.getParent() == cataLog.getId()) {
				throw new DaoException("Catalog's parent can not same as it's id.");
			}
			if (cataLog.getId() == getRootCatalog().getId()) {
				throw new DaoException("Root Catalog can not update.");
			}
			if (checkLoop(cataLog.getId(), cataLog.getParent())) {
				throw new DaoException("Parent Catalog存在循环嵌套。");
			}
		}
	}

	private boolean checkLoop(Integer id, Integer parent) throws DaoException {
		while (parent != null) {
			if (id.equals(parent)) {
				return true;
			} else {
				Catalog c = getCatalog(parent);
				parent = c != null ? c.getParent() : null;
			}
		}
		return false;
	}

	@Override
	public void updateCatalog(Catalog cataLog) throws DaoException {
		checkCatalog(cataLog, true);
		try {
			if (update.updateCatalog(cataLog) == 0) {
				throw new IllegalArgumentException("Catalog not exist for update: " + cataLog.getId());
			}
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	@Override
	public void moveCatalog(int catalogId, int parent) throws DaoException {
		if (checkLoop(catalogId, parent)) {
			throw new DaoException("Parent Catalog存在循环嵌套。");
		}
		try {
			if (move.moveCatalog(catalogId, parent) == 0) {
				throw new IllegalArgumentException("Catalog not exist for move: " + catalogId);
			}
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	@Override
	public void removeCatalog(int id) throws DaoException {
		if (id == getRootCatalog().getId()) {
			throw new DaoException("Root Catalog can not remove.");
		}
		try {
			if (delete.update(id) == 0) {
				throw new IllegalArgumentException("Catalog not exist for delete: " + id);
			}
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}
}
